/*************************************************************************
	> File Name: alarm_mutex.c
	> Author: chen
	> Mail: chen_tmacy@foxmail.com
	> Created Time: 2015年01月04日 星期日 12时17分57秒
    > note: 在一个线程中处理多个闹钟请求。time_t是时间数据，alarm_t包含
    > 这个时间数据，就可以根据时间进行排序。有一个链表将所有的请求连接起来
    > 互斥量alarm_mutex负责协调闹钟请求列表
 ************************************************************************/

#include<pthread.h>
#include"errors.h"
#include<time.h>


typedef struct alarm_tag{
    struct alarm_tag    *link;
    int                 seconds;
    time_t              time;
    char                message[64];
}alarm_t;

pthread_mutex_t alarm_mutex = PTHREAD_MUTEX_INITIALIZER;
alarm_t * alarm_list = NULL;

void * alarm_thread(void* arg){
    alarm_t     *alarm;
    int         sleep_time;
    time_t      now;
    int         status;

    while(1){
        status = pthread_mutex_lock(&alarm_mutex);
        if(status != 0)
            err_abort(status,"Lock mutext");
        alarm = alarm_list;

        if(alarm == NULL){
            sleep_time = 1;
        }else{
            alarm_list = alarm->link;
            now = time(NULL);
            if(alarm->time <= now){
                sleep_time = 0;
            }else{
                sleep_time = alarm->time - now;
            }
        
#ifdef DEBUG
            printf("[waiting : %d(%d) \" %s\"]\n",(int)alarm->time,
                            (int)sleep_time,alarm->message);
#endif

        }
        status = pthread_mutex_unlock(&alarm_mutex);
        if(status != 0){
            err_abort(status,"Unlock mutex");
        }
        if(sleep_time > 0){
            sleep(sleep_time);
        }else{
            sched_yield();
        }
        
        if(alarm != NULL){
            printf("alarm : (%d) %s\n",alarm->seconds,alarm->message);
            free(alarm);
        }
    }
}

int main(int argc ,char *argv[]){
    int     status;
    char    line[128];
    alarm_t *alarm, **last,*next;
    pthread_t thread;

    status = pthread_create(&thread,NULL,alarm_thread,NULL);
    if(status != 0){
        err_abort(status,"Create alarm thread");
    }
    #ifdef DEBUG
    printf("create thread!\n");
    #endif

    while(1){
        printf("alarm >");
        if(fgets(line,sizeof(line),stdin) == NULL) exit(0);
        if(strlen(line) <= 1) continue;
        alarm = (alarm_t *) malloc(sizeof(alarm_t));

        if(alarm == NULL)
            errno_abort("Allocate alarm");
        
        if(sscanf(line,"%d %64[^\n]",&alarm->seconds,alarm->message) < 2){
            fprintf(stderr,"Bad commmand\n");
            free(alarm);
        }else{
            puts("before main thread lock_mutex");
            status = pthread_mutex_lock(&alarm_mutex);
            if(status != 0)
                err_abort(status,"Lock mutex");
            alarm->time = time(NULL) + alarm->seconds;

            last = &alarm_list;
            next = alarm_list;

            while(next != NULL){
                if(next->time >= alarm->time){
                    alarm->link = next;
                    *last = alarm;
                    break;
                }
                last = &next->link;
                next = next->link;
            }

            if(next == NULL){
                *last = alarm;//last 保存前一个alarm->link地址
                alarm->link = NULL;
            }

            #ifdef DEBUG
            printf("[list:");
            for(next = alarm_list; next != NULL;next = next->link){
                printf("%d(%d)[\"%s\"] ",(int)next->time,
                       (int)(next->time-time(NULL)),next->message);
            }
            printf("]\n");
            #endif

            status = pthread_mutex_unlock(&alarm_mutex);
            puts("after main thread unlock");

            if(status!= 0){
                err_abort(status,"unlock mutex");
            }
        }
    }
    return 0;
}



